package com.empire.framework.security.core.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.empire.framework.common.encrypt.*;
import com.empire.framework.common.pkivo.*;
import com.empire.framework.common.util.crypto.Sm3Util;
import com.empire.framework.common.util.http.OkHttpUtil;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 第三方令牌核验API调用工具类（忽略SSL证书验证）
 */
@Slf4j
public class PkiVerifyApiClient {

    // 目标API的请求地址
    private static final String TOKEN_VERIFY_API_URL = "https://127.0.0.1:17446/query-general-data/service";
    // 审计中心接口地址
    private static final String SJZX_API_URL = "https://139.66.1.120/query-general-data/service";

    public static final String RESOURCE_ID_USER_VALIDATE = "/api-A-330100000000-0189-OTHER-1723539272971";
    public static final String RESOURCE_ID_APP_VALIDATE = "/api-A-330100000000-0189-OTHER-1723541877958";
    public static final String RESOURCE_ID_USER_TOKEN_INFO =     "/api-A-330100000000-0189-OTHER-1723541217058";
    public static final String RESOURCE_ID_USER_TOK_INFO =     "/api-A-330100000000-0189-OTHER-1723543810804";
    public static final String RESOURCE_ID_APP_INFO =     "/api-A-330100000000-0189-OTHER-1723542196425";
    public static final String RESOURCE_ID_TOKEN_OPERATE =     "/api-A-330100000000-0189-OTHER-1723542953237";
    public static final String TOKEN_OPERATE_KEY = "65f7e575446e77c1c19b9026f9ab922ab1869786";

    // 短信相关接口
    private static final String MESSAGE_API_URL = "https://127.0.0.1:17446/query-general-data/message";
    public static final String APP_CODE = "A-330100000000-0302";
    public static final String MESSAGE_SERVER_CODE = "SER000136";
    public static final String MESSAGE_TEMPLATE_CODE = "TEM000073";
    public static final String MESSAGE_SIGN_CODE = "SIGN000048";
    public static final String RESOURCE_ID_MESSAGE_PUSH = "/message-push";

    // 加密
    public static final String RESOURCE_ID_JIAM = "/api-A-330100000000-0207-OTHER-1728633011019";
    // 解密
    public static final String RESOURCE_ID_JIEM = "/api-A-330100000000-0207-OTHER-1728634560498";
    // 完整性验证
    public static final String RESOURCE_ID_MP_VERIFY = "/api-A-330100000000-0207-OTHER-1728635493584";
    // 固定加密类型
    public static final String ENCRYPT_KEY_TYPE = "1026";




    // -------------------------- 3.2.1 加密接口 --------------------------
    /**
     * 调用加密接口（对应3.2.1.1.2接口一）
     * @param plaintext 需要加密的明文
     * @return 加密响应结果（含密文、随机数）
     */
    public static EncryptResponse encrypt(String plaintext) {
        // 1. 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("app_code", APP_CODE);
        headers.put("resource_id", RESOURCE_ID_JIAM);
        headers.put("task_id", "*");

        // 2. 构建请求体
        EncryptRequest requestBody = new EncryptRequest();
        requestBody.setPlaintext(plaintext);
        requestBody.setKeyType(ENCRYPT_KEY_TYPE);

        // 3. 打印请求日志（脱敏敏感信息）
        log.info("发起加密请求：appCode=[{}], resourceId=[{}], 明文长度=[{}]",
                maskSensitiveInfo(APP_CODE),
                RESOURCE_ID_JIAM,
                plaintext != null ? plaintext.length() : 0);

        try {
            // 4. 调用加密接口（复用TOKEN_VERIFY_API_URL，若接口地址不同需单独定义常量）
            String result = OkHttpUtil.getInstance().postJson(
                    TOKEN_VERIFY_API_URL,
                    requestBody,
                    headers
            );

            // 5. 处理响应
            if (StrUtil.isNotEmpty(result)) {
                log.info("加密接口响应：result=[{}]", result);
                return JSONObject.parseObject(result, EncryptResponse.class);
            }

            // 空响应处理
            EncryptResponse errorResponse = new EncryptResponse();
            errorResponse.setSuccess("false");
            errorResponse.setErrorCode("9999");
            errorResponse.setErrorMsg("加密失败：接口返回空内容");
            return errorResponse;

        } catch (Exception e) {
            log.error("加密API调用失败（appCode=[{}], resourceId=[{}]",
                    maskSensitiveInfo(APP_CODE),
                    RESOURCE_ID_JIAM,
                    e);
            EncryptResponse errorResponse = new EncryptResponse();
            errorResponse.setSuccess("false");
            errorResponse.setErrorCode("9999");
            errorResponse.setErrorMsg("加密失败：" + e.getMessage());
            return errorResponse;
        }
    }

    // -------------------------- 3.2.2 解密接口 --------------------------
    /**
     * 调用解密接口（对应3.2.2.1.2接口二）
     * @param plainText 需要解密的密文
     * @param pucRandom 加密时返回的随机数
     * @return 解密响应结果（含解密后的明文）
     */
    public static DecryptResponse decrypt(String plainText, String pucRandom) {
        // 1. 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("app_code", APP_CODE);
        headers.put("resource_id", RESOURCE_ID_JIEM);
        headers.put("task_id", "*");

        // 2. 构建请求体
        DecryptRequest requestBody = new DecryptRequest();
        requestBody.setPlainText(plainText);
        requestBody.setKeyType(ENCRYPT_KEY_TYPE);
        requestBody.setPucRandom(pucRandom);

        // 3. 打印请求日志（脱敏敏感信息）
        log.info("发起解密请求：appCode=[{}], resourceId=[{}], 密文长度=[{}]",
                maskSensitiveInfo(APP_CODE),
                RESOURCE_ID_JIEM,
                plainText != null ? plainText.length() : 0);

        try {
            // 4. 调用解密接口
            String result = OkHttpUtil.getInstance().postJson(
                    TOKEN_VERIFY_API_URL,
                    requestBody,
                    headers
            );

            // 5. 处理响应
            if (StrUtil.isNotEmpty(result)) {
                log.info("解密接口响应：result=[{}]", result);
                return JSONObject.parseObject(result, DecryptResponse.class);
            }

            // 空响应处理
            DecryptResponse errorResponse = new DecryptResponse();
            errorResponse.setSuccess("false");
            errorResponse.setErrorCode("9999");
            errorResponse.setErrorMsg("解密失败：接口返回空内容");
            return errorResponse;

        } catch (Exception e) {
            log.error("解密API调用失败（appCode=[{}], resourceId=[{}]",
                    maskSensitiveInfo(APP_CODE),
                    RESOURCE_ID_JIEM,
                    e);
            DecryptResponse errorResponse = new DecryptResponse();
            errorResponse.setSuccess("false");
            errorResponse.setErrorCode("9999");
            errorResponse.setErrorMsg("解密失败：" + e.getMessage());
            return errorResponse;
        }
    }

    // -------------------------- 3.2.3 完整性验证接口 --------------------------
    /**
     * 调用完整性验证接口（对应3.2.3.1.2接口三）
     * @param plainText 需要验证完整性的明文
     * @return 验证响应结果（含签名串）
     */
    public static IntegrityVerifyResponse verifyIntegrity(String plainText) {
        // 1. 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("app_code", APP_CODE);
        headers.put("resource_id", RESOURCE_ID_MP_VERIFY); // 固定资源ID：/api8234
        headers.put("task_id", "*"); // 固定任务ID：*

        // 2. 构建请求体
        IntegrityVerifyRequest requestBody = new IntegrityVerifyRequest();
        requestBody.setPlainText(plainText);
        requestBody.setKeyType("39"); // 固定加密类型：39

        // 3. 打印请求日志（脱敏敏感信息）
        log.info("发起完整性验证请求：appCode=[{}], resourceId=[{}], 明文长度=[{}]",
                maskSensitiveInfo(APP_CODE),
                RESOURCE_ID_MP_VERIFY,
                plainText != null ? plainText.length() : 0);

        try {
            // 4. 调用完整性验证接口
            String result = OkHttpUtil.getInstance().postJson(
                    TOKEN_VERIFY_API_URL,
                    requestBody,
                    headers
            );

            // 5. 处理响应
            if (StrUtil.isNotEmpty(result)) {
                log.info("完整性验证接口响应：result=[{}]", result);
                return JSONObject.parseObject(result, IntegrityVerifyResponse.class);
            }

            // 空响应处理
            IntegrityVerifyResponse errorResponse = new IntegrityVerifyResponse();
            errorResponse.setSuccess("false");
            errorResponse.setErrorCode("9999");
            errorResponse.setErrorMsg("完整性验证失败：接口返回空内容");
            return errorResponse;

        } catch (Exception e) {
            log.error("完整性验证API调用失败（appCode=[{}], resourceId=[{}]",
                    maskSensitiveInfo(APP_CODE),
                    RESOURCE_ID_MP_VERIFY,
                    e);
            IntegrityVerifyResponse errorResponse = new IntegrityVerifyResponse();
            errorResponse.setSuccess("false");
            errorResponse.setErrorCode("9999");
            errorResponse.setErrorMsg("完整性验证失败：" + e.getMessage());
            return errorResponse;
        }
    }

    /**
     * 调用消息消息推送接口
     * @param taskId 任务ID
     * @param variables 模版变量（body参数，模板有变量时必传）
     * @param receivers 接收人员信息（body参数）
     * @return 推送消息推送推送推送响应结果
     */
    public static MessageSendResponse pushMessage(
            String taskId,
            List<MessageVariable> variables,
            List<MessageReceiver> receivers) {

        // 1. 构建请求头
        Map<String, String> headers = new HashMap<>();
        headers.put("app_code", APP_CODE);
        headers.put("resource_id", RESOURCE_ID_MESSAGE_PUSH);
        headers.put("task_id", taskId);

        // 2. 构建请求体
        MessagePushRequest requestBody = new MessagePushRequest();
        requestBody.setServerCode(MESSAGE_SERVER_CODE);
        requestBody.setTemplateCode(MESSAGE_TEMPLATE_CODE);
        requestBody.setSignCode(MESSAGE_SIGN_CODE);
        requestBody.setVariables(variables);
        requestBody.setReceivers(receivers);
        requestBody.setChannels(List.of(2));

        // 3. 打印请求日志（脱敏敏感信息）
        log.info("发起消息推送请求：appCode=[{}], serverCode=[{}], templateCode=[{}], 接收人数=[{}], 渠道=[{}]",
                maskSensitiveInfo(APP_CODE),
                MESSAGE_SERVER_CODE,
                MESSAGE_TEMPLATE_CODE,
                receivers != null ? receivers.size() : 0,
                2);

        try {
            // 4. 调用消息推送接口
            String result = OkHttpUtil.getInstance().postJson(
                    MESSAGE_API_URL,
                    requestBody,
                    headers
            );

            // 5. 处理响应
            if (StrUtil.isNotEmpty(result)) {
                log.info("消息推送响应：result=[{}]", result);
                return JSONObject.parseObject(result, MessageSendResponse.class);
            }

            // 空响应处理
            MessageSendResponse errorResponse = new MessageSendResponse();
            errorResponse.setErrorCode(9999);
            errorResponse.setErrorMessage("消息推送失败：接口返回空内容");
            return errorResponse;

        } catch (Exception e) {
            log.error("消息推送API调用失败（appCode=[{}], serverCode=[{}]",
                    maskSensitiveInfo(APP_CODE),
                    MESSAGE_SERVER_CODE,
                    e);
            MessageSendResponse errorResponse = new MessageSendResponse();
            errorResponse.setErrorCode(9999);
            errorResponse.setErrorMessage("消息推送失败：" + e.getMessage());
            return errorResponse;
        }
    }

    // -------------------------- 原有业务方法保持不变（仅补充日志便于排查） --------------------------
    public static TokenVerifyApiResponse callTokenVerifyApi(String appToken, String userToken, String userTokenId) {
        Map<String, String> headers = getHeaders(appToken, userToken, RESOURCE_ID_USER_VALIDATE);
        // 日志：打印请求参数（脱敏敏感信息，便于排查）
        log.info("发起用户令牌核验请求：appToken=[{}], userToken=[{}], userTokenId=[{}], headers=[{}]",
                maskSensitiveInfo(appToken), maskSensitiveInfo(userToken), userTokenId, headers);
        UserTokenVerifyApiRequest requestBody = new UserTokenVerifyApiRequest();
        requestBody.setUserTokenId(userTokenId);
        try {
            String result = OkHttpUtil.getInstance().postJson(TOKEN_VERIFY_API_URL, requestBody, headers);
            if (StrUtil.isNotEmpty(result)) {
                log.info("用户令牌核验响应：result=[{}]", result);
                return JSONObject.parseObject(result, TokenVerifyApiResponse.class);
            }
            TokenVerifyApiResponse errorResponse = new TokenVerifyApiResponse();
            errorResponse.setStatus_code("9999");
            errorResponse.setMessage("API调用失败，返回空内容。");
            return errorResponse;
        } catch (Exception e) {
            log.error("用户令牌核验API调用失败（appToken=[{}], userTokenId=[{}]",
                    maskSensitiveInfo(appToken), userTokenId, e);
            TokenVerifyApiResponse errorResponse = new TokenVerifyApiResponse();
            errorResponse.setStatus_code("9999");
            errorResponse.setMessage("API调用失败：" + e.getMessage());
            return errorResponse;
        }
    }

    public static UserTokenInfoResponse getUserTokenInfo(String appToken, String userToken, String userTokenId) {
        Map<String, String> headers = getHeaders(appToken, userToken, RESOURCE_ID_USER_TOKEN_INFO);
        // 日志：打印请求参数（脱敏敏感信息，便于排查）
        log.info("发起用户令牌信息查询请求：appToken=[{}], userToken=[{}], userTokenId=[{}]",
                maskSensitiveInfo(appToken), maskSensitiveInfo(userToken), userTokenId);
        UserTokenVerifyApiRequest requestBody = new UserTokenVerifyApiRequest();
        requestBody.setUserTokenId(userTokenId);
        try {
            String result = OkHttpUtil.getInstance().postJson(TOKEN_VERIFY_API_URL, requestBody, headers);
            if (StrUtil.isNotEmpty(result)) {
                log.info("用户令牌信息查询响应：result=[{}]", result);
                return JSONObject.parseObject(result, UserTokenInfoResponse.class);
            }
            UserTokenInfoResponse errorResponse = new UserTokenInfoResponse();
            errorResponse.setStatus_code("9999");
            errorResponse.setMessage("API调用失败，返回空内容。");
            return errorResponse;
        } catch (Exception e) {
            log.error("用户令牌核验API调用失败（appToken=[{}], userTokenId=[{}]",
                    maskSensitiveInfo(appToken), userTokenId, e);
            UserTokenInfoResponse errorResponse = new UserTokenInfoResponse();
            errorResponse.setStatus_code("9999");
            errorResponse.setMessage("API调用失败：" + e.getMessage());
            return errorResponse;
        }
    }

    /**
     * 调用第三方用户信息查询API
     * @param appToken  应用令牌（从请求头获取）
     * @param userToken 用户令牌（从请求头获取）
     * @param queryRequest 查询条件（pId/身份证号等可选参数，非null）
     * @return 用户信息查询响应
     */
    public static UserInfoQueryResponse getUserInfo(String appToken, String userToken, UserInfoQueryRequest queryRequest) {
        // 1. 组装请求头
        Map<String, String> headers = getHeaders(appToken, userToken, RESOURCE_ID_USER_TOK_INFO);

        // 2. 日志：打印请求参数（脱敏敏感信息，如身份证号、手机号）
        log.info("发起用户信息查询请求：appToken=[{}], userToken=[{}], 查询条件=[pId={}, idcard={}, userName={}, orgCode={}, policeNo={}]",
                maskSensitiveInfo(appToken),
                maskSensitiveInfo(userToken),
                queryRequest.getPId(),
                maskSensitiveInfo(queryRequest.getIdcard()), // 身份证号脱敏
                queryRequest.getUserName(),
                queryRequest.getOrgCode(),
                queryRequest.getPoliceNo());

        // 3. 调用 OkHttp 发送 POST 请求（复用原有 OkHttpUtil 实例）
        try {
            String result = OkHttpUtil.getInstance().postJson(
                    TOKEN_VERIFY_API_URL, // 同令牌核验的请求地址
                    queryRequest,         // 新增的查询请求体
                    headers               // 包含 Content-Type 的完整请求头
            );

            // 4. 处理响应：非空校验 + JSON 解析
            if (StrUtil.isNotEmpty(result)) {
                log.info("用户信息查询响应：result=[{}]", result);
                return JSONObject.parseObject(result, UserInfoQueryResponse.class);
            }

            // 5. 空响应处理
            UserInfoQueryResponse errorResponse = new UserInfoQueryResponse();
            errorResponse.setStatus_code("9999");
            errorResponse.setMessage("用户信息查询失败：接口返回空内容");
            return errorResponse;

        } catch (Exception e) {
            // 6. 异常处理（统一返回 9999 错误码）
            log.error("用户信息查询API调用失败（appToken=[{}], 查询条件pId=[{}]",
                    maskSensitiveInfo(appToken),
                    queryRequest.getPId(),
                    e);
            UserInfoQueryResponse errorResponse = new UserInfoQueryResponse();
            errorResponse.setStatus_code("9999");
            errorResponse.setMessage("用户信息查询失败：" + e.getMessage());
            return errorResponse;
        }
    }

    // -------------------------- 2.1.3 应用令牌核验 --------------------------
    /**
     * 核验应用令牌的有效性
     *
     * @param appToken   应用令牌（从请求头获取）
     * @param userToken  用户令牌（从请求头获取）
     * @param appTokenId 应用令牌ID（必传）
     */
    public static void verifyAppToken(String appToken, String userToken, String appTokenId) {
        // 1. 构建请求头
        Map<String, String> headers = getHeaders(appToken, userToken, RESOURCE_ID_APP_VALIDATE);

        // 2. 构建请求体（必传appTokenId）
        AppTokenVerifyRequest request = new AppTokenVerifyRequest();
        request.setAppTokenId(appTokenId);

        // 3. 打印请求日志（脱敏敏感信息）
        log.info("发起应用令牌核验请求：appToken=[{}], userToken=[{}], appTokenId=[{}]",
                maskSensitiveInfo(appToken),
                maskSensitiveInfo(userToken),
                maskSensitiveInfo(appTokenId));

        try {
            // 4. 调用接口
            String result = OkHttpUtil.getInstance().postJson(TOKEN_VERIFY_API_URL, request, headers);

            // 5. 处理响应
            if (result != null) {
                log.info("应用令牌核验响应：{}", result);

                JSONObject.parseObject(result, TokenVerifyResponse.class);
                return;
            }

            // 空响应处理
            TokenVerifyResponse error = new TokenVerifyResponse();
            error.setStatus_code("9999");
            error.setMessage("应用令牌核验失败：响应为空");

        } catch (Exception e) {
            log.error("应用令牌核验API调用失败（appTokenId=[{}]", maskSensitiveInfo(appTokenId), e);
            TokenVerifyResponse error = new TokenVerifyResponse();
            error.setStatus_code("9999");
            error.setMessage("应用令牌核验失败：" + e.getMessage());
        }
    }

    // -------------------------- 2.1.4 应用令牌信息获取 --------------------------
    /**
     * 通过应用令牌ID获取应用令牌信息
     * @param appToken  应用令牌（从请求头获取）
     * @param userToken 用户令牌（从请求头获取）
     * @param appTokenId 应用令牌ID（必传）
     * @return 令牌信息结果
     */
    public static AppTokenInfoResponse getAppTokenInfo(String appToken, String userToken, String appTokenId) {
        // 1. 构建请求头
        Map<String, String> headers = getHeaders(appToken, userToken, RESOURCE_ID_APP_INFO);

        // 2. 构建请求体
        AppTokenVerifyRequest request = new AppTokenVerifyRequest();
        request.setAppTokenId(appTokenId);

        // 3. 打印请求日志
        log.info("发起应用令牌信息查询：appToken=[{}], userToken=[{}], appTokenId=[{}]",
                maskSensitiveInfo(appToken),
                maskSensitiveInfo(userToken),
                maskSensitiveInfo(appTokenId));

        try {
            // 4. 调用接口
            String result = OkHttpUtil.getInstance().postJson(TOKEN_VERIFY_API_URL, request, headers);

            // 5. 处理响应
            if (result != null) {
                log.info("应用令牌信息响应：{}", result);
                return JSONObject.parseObject(result, AppTokenInfoResponse.class);
            }

            // 空响应处理
            AppTokenInfoResponse error = new AppTokenInfoResponse();
            error.setStatus_code("9999");
            error.setMessage("应用令牌信息获取失败：响应为空");
            return error;

        } catch (Exception e) {
            log.error("应用令牌信息API调用失败（appTokenId=[{}]", maskSensitiveInfo(appTokenId), e);
            AppTokenInfoResponse error = new AppTokenInfoResponse();
            error.setStatus_code("9999");
            error.setMessage("应用令牌信息获取失败：" + e.getMessage());
            return error;
        }
    }

    // -------------------------- 2.1.5 令牌续期下线 --------------------------
    /**
     * 令牌续期或下线操作
     * @param appToken  应用令牌（从请求头获取）
     * @param userToken 用户令牌（从请求头获取）
     * @param request 操作请求参数（包含tokenId、type、action等必传字段）
     * @return 操作结果
     */
    public static TokenOperateResponse operateToken(String appToken, String userToken, TokenOperateRequest request) {
        // 1. 参数校验（必传字段检查）
        validateOperateRequest(request);

        // 2. 计算签名（sm3(参数拼接 + 固定key)）
        String sign = calculateSign(request);
        request.setCallerSign(sign);

        // 3. 构建请求头
        Map<String, String> headers = getHeaders(appToken, userToken, RESOURCE_ID_TOKEN_OPERATE);

        // 4. 打印请求日志（脱敏敏感信息）
        log.info("发起令牌操作请求：appToken=[{}], userToken=[{}], tokenId=[{}], type=[{}], action=[{}]",
                maskSensitiveInfo(appToken),
                maskSensitiveInfo(userToken),
                maskSensitiveInfo(request.getTokenId()),
                request.getType(),
                request.getAction());

        try {
            // 5. 调用接口
            String result = OkHttpUtil.getInstance().postJson(TOKEN_VERIFY_API_URL, request, headers);

            // 6. 处理响应
            if (result != null) {
                log.info("令牌操作响应：{}", result);
                return JSONObject.parseObject(result, TokenOperateResponse.class);
            }

            // 空响应处理
            TokenOperateResponse error = new TokenOperateResponse();
            error.setStatus_code("9999");
            error.setMessage("令牌操作失败：响应为空");
            return error;

        } catch (Exception e) {
            log.error("令牌操作API调用失败（tokenId=[{}], action=[{}]",
                    maskSensitiveInfo(request.getTokenId()), request.getAction(), e);
            TokenOperateResponse error = new TokenOperateResponse();
            error.setStatus_code("9999");
            error.setMessage("令牌操作失败：" + e.getMessage());
            return error;
        }
    }

    // -------------------------- 工具方法 --------------------------
    /**
     * 构建请求头（复用逻辑，包含Content-Type）
     */
    private static Map<String, String> getHeaders(String appToken, String userToken, String resourceId) {
        Map<String, String> headers = new HashMap<>();
        headers.put("app_token_id", appToken);
        headers.put("user_token_id", userToken);
        headers.put("resource_id", resourceId);
        return headers;
    }

    /**
     * 敏感信息脱敏（保留前2位和后2位）
     */
    private static String maskSensitiveInfo(String info) {
        return info;
//        if (info == null || info.length() <= 4) {
//            return "***";
        //return info.substring(0, 2) + "***" + info.substring(info.length() - 2);
    }

    /**
     * 校验令牌操作请求的必传参数
     */
    private static void validateOperateRequest(TokenOperateRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("令牌操作请求参数不能为空");
        }
        if (request.getTokenId() == null) {
            throw new IllegalArgumentException("令牌ID（tokenId）为必填项");
        }
        if (request.getType() == null || (!"app".equals(request.getType()) && !"user".equals(request.getType()))) {
            throw new IllegalArgumentException("令牌类型（type）必须为app或user");
        }
        if (request.getAction() == null || (!"offline".equals(request.getAction()) && !"renew".equals(request.getAction()))) {
            throw new IllegalArgumentException("操作类型（action）必须为offline或renew");
        }
        if (request.getCalledId() == null || !"cli".equals(request.getCalledId())) {
            throw new IllegalArgumentException("调用方（calledId）必须为cli");
        }
        if (request.getCallerTimestamp() == null) {
            throw new IllegalArgumentException("时间戳（callerTimestamp）为必填项");
        }
        if (request.getCallerNounce() == null) {
            throw new IllegalArgumentException("随机数（callerNounce）为必填项");
        }
    }

    /**
     * 计算签名（sm3(参数值拼接 + 固定key)，结果转为Base64编码）
     * 拼接顺序：tokenId + type + action + calledId + callerTimestamp + callerNounce + key
     */
    private static String calculateSign(TokenOperateRequest request) {
        // 1. 拼接原始签名串
        StringBuilder signSource = new StringBuilder();
        signSource.append(request.getTokenId())
                .append(request.getType())
                .append(request.getAction())
                .append(request.getCalledId())
                .append(request.getCallerTimestamp())
                .append(request.getCallerNounce())
                .append(TOKEN_OPERATE_KEY); // 65f7e575446e77c1c19b9026f9ab922ab1869786

        // 2. 计算SM3哈希（假设Sm3Util.sm3返回字节数组，若返回16进制字符串需先转字节数组）
        byte[] sm3Hash = Sm3Util.sm3(signSource.toString().getBytes(StandardCharsets.UTF_8));
        // 若Sm3Util.sm3返回的是16进制字符串，需先转为字节数组：
        // String sm3Hex = Sm3Util.sm3(signSource.toString());
        // byte[] sm3Hash = hexToBytes(sm3Hex);

        // 3. 对哈希结果进行Base64编码
        String base64Sign = Base64.getEncoder().encodeToString(sm3Hash);

        log.debug("签名原始串：{}，SM3哈希(Base64)：{}", signSource, maskSensitiveInfo(base64Sign));
        return base64Sign;
    }

    // 辅助方法：将16进制字符串转为字节数组（如果SM3工具返回的是16进制字符串时使用）
    private static byte[] hexToBytes(String hex) {
        int len = hex.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return bytes;
    }
}
